from httpx import AsyncClient
from loguru import logger
import asyncio

logger.add("redeem_code.log", rotation="10 MB", enqueue=True)

PEPSI_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) Appl"
                  "eWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661."
                  "102 Safari/537.36",
    "Referer": "https://billboardchartstars.com/",
}


def handle_errors(data: dict):
    if "errors" in data:
        messages = [error["message"] for error in data["errors"]]
        raise Exception(
                "Ошибки при отправке запросов " + "\n".join(messages))


async def redeem_code(
        client: AsyncClient,
        code: str):
    response = await client.post(
             "https://billboard-storefrontapi.nftco.com/graphql",
                    json={
                        "operationName": "RedeemCode",
                        "query": "mutation RedeemCode($code: String!) {\n    redeemCode(code: $code) {\n    redemptionProgram {\n    blockSlug\n    enabled\n    heroImageUrl\n    id\n    name\n    redemptionEnabled\n    slug\n    storefrontId\n    subtitle\n    termsConditions\n    title\n  }\n}}\n",
                        "variables": {
                            "code": code
                        }
                    }
                )
    data = response.json()
    handle_errors(data)


async def redeem_giveaway(
        client: AsyncClient,
        code: str):
    response = await client.post(
                    "https://billboard-storefrontapi.nftco.com/graphql",
                    json={
                        "operationName": "RedeemGiveaway",
                        "query": "mutation RedeemGiveaway($code: String!) {\n    redeemGiveaway(code: $code) {\n      giveaway {\n    blockSlug\n    enabled\n    heroImageUrl\n    id\n    name\n    redemptionEnabled\n    slug\n    storefrontId\n    subtitle\n    termsConditions\n    title\n  }\n    }\n    }\n",
                        "variables": {
                            "code": code
                        }
                    }
                )
    data = response.json()
    handle_errors(data)


async def redeem_worker(q: asyncio.Queue, code: str):
    while True:
        proxy, access_token = await q.get()

        try:
            async with AsyncClient(
                    headers={
                        "Authorization": "Bearer " + access_token,
                        **PEPSI_HEADERS
                    },
                    proxies={
                        "http://": proxy,
                        "https://": proxy
                    },
                    http2=True) as client:

                logger.info("Попытка отправить код {}", code)
                errors = []

                try:
                    await redeem_code(client, code)
                except Exception as e:
                    errors.append(e)
                try:
                    await redeem_giveaway(client, code)
                except Exception as e:
                    errors.append(e)

                if len(errors) > 1:
                    raise errors[1]

                logger.info("Успешная отправка кода {}", code)
        except Exception:
            logger.exception("Ошибка при отправке кода")


async def main():
    q = asyncio.Queue()

    for account in open("accounts.txt", "r+").read().strip().split("\n"):
        args = account.split(";")
        proxy, access_token = args[-1], args[-2]

        q.put_nowait((proxy, access_token))

    code = input("Код -> ")

    tasks = [asyncio.create_task(redeem_worker(q, code))
             for _ in range(int(input("Кол-во потоков -> ")))]

    await asyncio.gather(*tasks)


if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    loop.run_until_complete(main())
